package com.demo.doc_pdf_demo.util;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * 使用libreoffice、unoconv工具，转换pdf
 *
 * @author L.Wen
 * @date 2021/6/16 18:35
 * <p>
 * # Getting Started
 * <p>
 * ### Linux服务器上需要安装转换软件：libreoffice、unoconv
 * <p>
 * 安装步骤：
 * <p>
 * 1、官网下载：https://downloadarchive.documentfoundation.org/libreoffice/old/5.4.7.2/rpm/x86_64/
 * <p>
 * 2、LibreOffice_5.4.7.2_Linux_x86-64_rpm.tar.gz、LibreOffice_5.4.7.2_Linux_x86-64_rpm_langpack_zh-CN.tar.gz
 * <p>
 * 3、tar -zxvf 解压后安装：
 * ```shell script
 * sudo yum install ./LibreOffice_5.4.7.2_Linux_x86-64_rpm/RPMS/*.rpm
 * sudo yum install ./LibreOffice_5.4.7.2_Linux_x86-64_rpm_langpack_zh-CN/RPMS/*.rpm
 * sudo yum install libreoffice-headless
 * sudo yum install libreoffice-writer
 * ```
 * 4、下载unoconv：wget https://github.com/dagwieers/unoconv/archive/master.zip
 * <p>
 * 5、解压：unzip unoconv-master.zip
 * <p>
 * 6、创建目录：mkdir /usr/local/unoconv/
 * <p>
 * 7、拷贝文件：cd unoconv-master，mv * /usr/local/unoconv/
 * <p>
 * 8、创建软链接：ln -s /usr/local/unoconv/unoconv /usr/bin/unoconv
 * <p>
 * 9、字体处理：将Windows下的Fonts，如：C:\Windows\Fonts，压缩成Fonts.zip压缩包。将压缩包拷贝到Linux目录下，执行如下命令即可：
 * ```shell script
 * unzip Fonts.zip
 * mkdir /usr/share/fonts/win
 * cp Fonts/* /usr/share/fonts/win
 * cd /usr/share/fonts/win
 * chmod -Rf 755 *
 * yum install mkfontscale fontconfig
 * mkfontscale
 * mkfontdir
 * fc-cache –fv
 * ```
 * 10、转换：unoconv -f p
 *
1、libreoffice服务的启动
启动指令是

libreoffice --headless --accept="socket,host=0.0.0.0,port=8100;urp;" --nofirststartwizard &

注意host要写0.0.0.0，不要写127.0.0.1，再后面遇到的问题中会进一步说明。

2、libreoffice的测试方法
（1）libreoffice指令测试

libreoffice  --invisible --convert-to  pdf  test.docx
 *
 */
//@Log4j2
//public class Doc2pdfLibreofficeUtil {
//    /**
//     * 操作系统名称：windows
//     */
//    private static final String SYS_WIN = "Windows";
//
//    public static final String RES_CODE_SUCCESS = "200";
//
//    public static final String RES_CODE_FAILURE = "400";
//    /**
//     * @param docxPath doc文件的完整路径
//     * @return 生成pdf文件的完整路径
//     */
//    public synchronized static JSONObject doc2pdf(String docxPath) throws Exception {
//        JSONObject jsonObject;
//        if (StringUtils.isBlank(docxPath)) {
//            jsonObject = new JSONObject();
//            jsonObject.put("code", RES_CODE_FAILURE);
//            jsonObject.put("data", "docxPath is empty! ");
//            return jsonObject;
//        }
//        File sourceFile = new File(docxPath);
//        if (!sourceFile.exists()) {
//            jsonObject = new JSONObject();
//            jsonObject.put("code", RES_CODE_FAILURE);
//            jsonObject.put("data", "sourceFile is not exist! ");
//            return jsonObject;
//        }
//        try {
//            String osName = System.getProperty("os.name");
//            log.info("osName: {}", osName);
//            String command;
//            String ext = docxPath.substring(docxPath.lastIndexOf("."));
//            log.info("sourceFile ext: {}", ext);
//            // 把 .doc 或者 .docx 换成 .pdf
//            String path = docxPath.substring(0, docxPath.lastIndexOf("."));
//            String pdfPath = path + ".pdf";
//            if (osName.contains(SYS_WIN)) {
//                command = "soffice --convert-to pdf  -outdir " + pdfPath + " " + docxPath;
//            } else {
//                // Linux服务器上需要安装转换软件，请看README
////                command = "unoconv -f pdf " + docxPath;
//                command = docxPath;
//            }
//            String result = executeCommand(command);
//            if ("".equals(result) || result.contains("writer_pdf_Export")) {
//                jsonObject = new JSONObject();
//                jsonObject.put("code", RES_CODE_SUCCESS);
//                jsonObject.put("data", pdfPath);
//                return jsonObject;
//            }
//        } catch (Exception e) {
//            log.error("Exception: ", e);
//            throw e;
//        }
//        jsonObject = new JSONObject();
//        jsonObject.put("code", RES_CODE_FAILURE);
//        jsonObject.put("data", "Exception! ");
//        return jsonObject;
//    }
//
//    /**
//     * 命令执行
//     *
//     * @param command 命令行
//     * @return 执行结果
//     */
//    private static String executeCommand(String command) throws Exception {
//        ProcessBuilder pb = new ProcessBuilder("unoconv", "-f", "pdf", command);
//        pb.redirectErrorStream(true);
//        Process process = pb.start();
//
//        Worker worker = new Worker(process);
//        worker.start();
//        ProcessStatus ps = worker.getProcessStatus();
//        try {
//            worker.join(180000);
//            if (ps.exitCode == ProcessStatus.CODE_STARTED) {
//                // not finished
//                worker.interrupt();
//                throw new TimeoutException();
//            } else {
//                return worker.ps.output;
//            }
//        } catch (InterruptedException | TimeoutException e) {
//            // canceled by other thread.
//            worker.interrupt();
//            throw e;
//        } finally {
//            process.destroy();
//        }
//    }
//
//    private static class Worker extends Thread {
//        private final Process process;
//        private final ProcessStatus ps;
//
//        private Worker(Process process) {
//            this.process = process;
//            this.ps = new ProcessStatus();
//        }
//
//        @Override
//        public void run() {
//            try {
//                InputStream is = process.getInputStream();
//                try {
//                    ps.output = IOUtils.toString(is);
//                } catch (IOException ignore) {
//                }
//                ps.exitCode = process.waitFor();
//            } catch (InterruptedException e) {
//                Thread.currentThread().interrupt();
//            }
//        }
//
//        public ProcessStatus getProcessStatus() {
//            return this.ps;
//        }
//    }
//
//    public static class ProcessStatus {
//        public static final int CODE_STARTED = -257;
//        public volatile int exitCode;
//        public volatile String output;
//    }
//}

@Log4j2
public class Doc2pdfLibreofficeUtil {
    /**
     * 操作系统名称：windows
     */
    private static final String SYS_WIN = "Windows";

    public static final String RES_CODE_SUCCESS = "200";

    public static final String RES_CODE_FAILURE = "400";

    /**
     * @param docxPath doc文件的完整路径
     * @return 生成pdf文件的完整路径
     */
    public static synchronized JSONObject doc2pdf(String docxPath) throws IOException, InterruptedException {
        String fileFolder;
        try{
            log.error("转换文件入参："+docxPath);
            fileFolder=docxPath.substring(0,docxPath.lastIndexOf(File.separator));
        }catch (Exception e){
            log.error("找不到系统/符号！");
            fileFolder=docxPath.substring(0,docxPath.lastIndexOf("/"));
        }
        JSONObject jsonObject;
        if (StringUtils.isBlank(docxPath)) {
            jsonObject = new JSONObject();
            jsonObject.put("code", RES_CODE_FAILURE);
            jsonObject.put("data", "docxPath is empty! ");
            return jsonObject;
        }
        File sourceFile = new File(docxPath);
        if (!sourceFile.exists()) {
            jsonObject = new JSONObject();
            jsonObject.put("code", RES_CODE_FAILURE);
            jsonObject.put("data", "sourceFile is not exist! ");
            return jsonObject;
        }
        try {
            String osName = System.getProperty("os.name");
            log.info("osName: {}", osName);
            String command = "";
            String ext = docxPath.substring(docxPath.lastIndexOf(".") + 1);
            log.info("sourceFile ext: {}", ext);
            String pdfPath = docxPath.replace(ext, "pdf");
            if (osName.contains(SYS_WIN)) {
                command = "soffice --convert-to pdf  -outdir " + pdfPath + " " + docxPath;
            } else {
                // Linux服务器上需要安装转换软件，请看README
//                command = "unoconv -f pdf " + docxPath;
                log.error("linux正在转换文件："+docxPath);
                command = "libreoffice --invisible --convert-to pdf " + docxPath+" --outdir "+fileFolder;
            }
            String result = executeCommand(command);
            if ("".equals(result) || result.contains("writer_pdf_Export")||result.contains("writer_web_pdf_Export")) {
                jsonObject = new JSONObject();
                jsonObject.put("code", RES_CODE_SUCCESS);
                jsonObject.put("data", pdfPath);
                log.error("文件转换成功："+jsonObject);
                return jsonObject;
            }
        } catch (Exception e) {
            log.error("Exception: ", e);
            throw e;
        }
        jsonObject = new JSONObject();
        jsonObject.put("code", RES_CODE_FAILURE);
        jsonObject.put("data", "Exception! ");
        log.error("文件转换失败："+jsonObject);
        return jsonObject;
    }

    /**
     * 命令执行
     *
     * @param command
     * @return
     */
    private static String executeCommand(String command) throws IOException, InterruptedException {
        StringBuilder output = new StringBuilder();
        Process p;
        InputStreamReader inputStreamReader = null;
        BufferedReader reader = null;
        try {
            p = Runtime.getRuntime().exec(command);
            p.waitFor();
            inputStreamReader = new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8);
            reader = new BufferedReader(inputStreamReader);
            String line = "";
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }
        } catch (IOException | InterruptedException e) {
            log.error("execute exception: ", e);
            throw e;
        } finally {
            IOUtils.closeQuietly(reader);
            IOUtils.closeQuietly(inputStreamReader);
        }
        log.info(output.toString());
        return output.toString();
    }
}